﻿using System;
using System.Collections; 
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Timers;
using System.Text.RegularExpressions;
using System.Net.NetworkInformation;
using CWCS.Entity;
using COMResolution;
using CWCS.Common.Log;
using CWCS.Entity.SRM;

namespace CWCS.BLL
{
    public delegate void DNotifyType(string srmno, string srmport, string eNotify, object oNotify);//定义一个消息代理传值给UIL

    public class BLLSRM : BLLBase
    {
        private CRLSRMControl OSRM;   //构造函数中new
        private string m_strSRMNo, m_strport, m_ip;
        private LogHelper log ;
        private LogHelper logConnect;
        private int aisle;
        private Timer CheckTimer = null;
        private Timer GetStatusTimer = null;
        public event DNotifyType ENotifyTypeEventHandler;//传递给UIL层各种消息的事件  
        public delegate void Notify(string type, string msg);
        public event Notify ENotify;
        private Timer DrawStatusTimer = null;
        public Hashtable loght = Hashtable.Synchronized(new Hashtable());

        public Timer CheckConnectTimer
        {
            get
            {
                if (CheckTimer == null)
                {
                    CheckTimer = new Timer();
                }
                return CheckTimer;
            }
        }

        public Timer GetSCStatusTimer
        {
            get
            {
                if (GetStatusTimer == null)
                { GetStatusTimer = new Timer(); }
                return GetStatusTimer;
            }
        }
        public Timer DrawSCStatusTimer
        {
            get
            {
                if (DrawStatusTimer == null)
                { DrawStatusTimer = new Timer(); }
                return DrawStatusTimer;
            }
        }
        public BLLSRM(string strsrmno, string ipaddress, int port, int row)//构造函数
        {
            m_strSRMNo = strsrmno;
            m_strport = port.ToString();
            m_ip = ipaddress;
            aisle = row * 2;
            log = new LogHelper("SC");
            logConnect = new LogHelper("SCConnect");
            OSRM = new CRLSRMControl(m_strSRMNo, ipaddress, port);

            CheckConnectTimer.Interval = Convert.ToInt32(System.Configuration.ConfigurationSettings.AppSettings["CheckConnectTimer"]);
            CheckConnectTimer.Elapsed += new ElapsedEventHandler(CheckConnectTimer_Elapsed);//若连接失败则检测网络直到连接上了

            GetSCStatusTimer.Interval = Convert.ToInt32(System.Configuration.ConfigurationSettings.AppSettings["GetStatusTime"]);
            GetSCStatusTimer.Elapsed += new ElapsedEventHandler(GetSCStatusTimer_Elapsed);//获取卫星小车信息Timer事件
            DrawSCStatusTimer.Interval = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["DrawTime"]);
            DrawSCStatusTimer.Elapsed += new ElapsedEventHandler(DrawSCStatusTimer_Elapsed);//获取堆垛机信息Timer事件
            DrawSCStatusTimer.Start();
            OSRM.AnalyseMessageEvent += new CRLSRMControl.AnalyseMessageEventHandler(OSRM_AnalyseMessageEvent);//AnalyseMessageEvent解析收到数据时事件的代理，传给BLL层
        }

        public BLLSRM()
        {
        }

        public int Run()//启动
        {
            if (m_strport == "4000")
            {
                CRCStatus srm_info = new CRCStatus();
                srm_info.scno = m_strSRMNo;
                srm_info.AisleNumber = aisle.ToString();
                srm_info.RackSide = "1";
                srm_info.RackPosition = "1";
                srm_info.RackPlace = "1";
                srm_info.RackLevel = "1";
                srm_info.RackDepth = "1";
                srm_info.AlarmMessage = "未连接";
                srm_info.scno = m_strSRMNo;
                string wcsModeInfo = "任务:" + getTasktype(srm_info.TaskType);
                string wcsForkInfo = ".货叉:" + getForktype(srm_info.ForkType);
                srm_info.LabelInfo = ".任务号:0.托盘1:.托盘2:.当前位置:无.模式:无" + ".状态:无" + ".起始地址:" + ".目标地址:" + "." + srm_info.AlarmMessage;
                srm_info.NewLabelInfo = wcsModeInfo + wcsForkInfo + srm_info.LabelInfo;
                list_srm_info.Add(srm_info);
            }
            if (OSRM.Startup())
            {
                GetSCStatusTimer.Start();
                WriteLog("C", "连接成功,IP地址:" + m_ip + ",堆垛机编号:" + m_strSRMNo + ",端口:" + m_strport);
                return 1;
            }
            else
            {
                CheckConnectTimer.Start();
                WriteLog("C", "连接失败,IP地址:" + m_ip + ",堆垛机编号:" + m_strSRMNo + ",端口:" + m_strport);
                return 0;
            }
        }
        private void DrawSCStatusTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (ENotifyTypeEventHandler != null && m_strport.Contains("400"))
                ENotifyTypeEventHandler(m_strSRMNo, m_strport, "", "");
        }
        private void OSRM_AnalyseMessageEvent(string CommandType, object msg) //解析收到数据的代理的参数,CommandType是break，connect等
        {
            CRCObject findcob = list_srm_object.Find(
                delegate (CRCObject info)
                {
                    return (info.ScNo == m_strSRMNo && info.Port == int.Parse(m_strport)); //如果这2个值满足了，就返回一个true或者false
                }
            );
            if (m_strport == "4000" && CommandType == "RecvData")
            {
                if (findcob != null)
                    findcob.connectstatus = (findcob.connectstatus == 1 ? 2 : 1);

                string result = crc.UpdateCRCStatus(m_strSRMNo, msg.ToString(), aisle.ToString(), findcob.zonecode);
                if (!string.IsNullOrEmpty(result))
                    WriteLog("S", "堆垛机编号:" + m_strSRMNo + result);
                //if (!string.IsNullOrEmpty(crc.GetAlarmInfo(m_strSRMNo, "", false))) //获取报警信息
                //    WriteLog(m_strSRMNo, crc.GetAlarmInfo(m_strSRMNo, "", false));

                if (ENotifyTypeEventHandler != null)
                    ENotifyTypeEventHandler(m_strSRMNo, m_strport, CommandType, msg);
            }
            else if (m_strport == "6000" && CommandType == "RecvData")
            {
                crc.GetAlarmInfo(m_strSRMNo, msg.ToString(), true);
            }
            else if (CommandType == "Break")
            {
                if (m_strport == "2000")
                {
                    CheckConnectTimer.Start();
                    GetSCStatusTimer.Stop();
                }
                if (findcob != null)
                    findcob.connectstatus = 0;
            }
            else if (CommandType == "Connect")
            {
                if (findcob != null)
                    findcob.connectstatus = 1;
                WriteLog("C", "连接成功,IP地址:" + m_ip + ",堆垛机编号:" + m_strSRMNo + ",端口:" + m_strport);
            }
        }

        private void CheckConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            CheckConnectTimer.Stop();
            if (!OSRM.IsConnected())
            {
                //QueueSpeech.AddQueue(string.Format("与{0}号堆垛机连接断开,系统开始尝试重连", m_strSRMNo.Substring(m_strSRMNo.Length - 1, 1)));
                if (OSRM.Startup())
                {
                    GetSCStatusTimer.Start();
                    //QueueSpeech.AddQueue(string.Format("与{0}号堆垛机重连成功", m_strSRMNo.Substring(m_strSRMNo.Length - 1, 1)));
                    WriteLog("C", "检测连接成功,IP地址:" + m_ip + ",堆垛机编号:" + m_strSRMNo + ",端口:" + m_strport);
                }
                else
                {
                    if (m_strport != "2000")
                    {
                        CheckConnectTimer.Start();
                    }
                    WriteLog("C", "检测连接失败,IP地址:" + m_ip + ",堆垛机编号:" + m_strSRMNo + ",端口:" + m_strport);
                }
            }
            else
                GetSCStatusTimer.Start();
        }

        private void GetSCStatusTimer_Elapsed(object sender, ElapsedEventArgs e) //获取卫星小车信息Timer事件
        {
            if (m_strport == "4000")
            {
                if (!OSRM.SendMsg(MessageHeader_NTI_4000)) //发送报头过去检测堆垛机的返回值，如果返回值为空的话就是没连接
                {
                    CheckConnectTimer.Start();
                    GetSCStatusTimer.Stop();
                }
            }
            else if (m_strport == "6000")
            {
                if (!OSRM.SendMsg(MessageHeader_NTI_6000))
                {
                    CheckConnectTimer.Start();
                    GetSCStatusTimer.Stop();
                }
            }
        }
        public static string RemoveNotNumber(string key)
        {
            return Regex.Replace(key, @"[^\d]*", "");
        }

        public bool SendCode(string scno, int type, int taskno, string destAdress, string fireflag, int forkNo = 1, int fork2taskno = 0)
        {
            try
            {
                destAdress = RemoveNotNumber(destAdress); //S0010010011
                byte[] msg = new byte[24];
                int fork2taskno1 = 0;
                int fork2taskno2 = 0;
                if (fork2taskno != 0)
                {
                    fork2taskno1 = fork2taskno / 256;
                    fork2taskno2 = fork2taskno % 256;
                }
                int taskno1 = taskno / 256;
                int taskno2 = taskno % 256;
                int actionpoint = 1;
                int aisle1 = 1;
                msg[0] = 0x01;
                msg[1] = 0x01;//messagecount
                msg[2] = (byte)fork2taskno1;
                msg[3] = (byte)fork2taskno2;
                msg[4] = (byte)taskno1;
                msg[5] = (byte)taskno2;
                msg[6] = (byte)type;//取: 112   放: 128   清除: 0
                msg[7] = 0x00;
                msg[8] = 0x00;
                msg[9] = (byte)forkNo;// 0x01货叉1  0x02货叉2  0x03货叉同取同放
                aisle1 = int.Parse(scno.Substring(scno.Length - 1));//堆垛机号 1-3
                //aisle1 = 1;
                // 取货完成 清除  &&  放货完成 清除
                if (string.IsNullOrEmpty(destAdress) && type == 0)
                {
                    for (int i = 12; i < 24; i++)
                    {
                        msg[i] = 0x00;
                    }
                }
                // 取放指令为：站台 需要配置
                else if (destAdress != null && destAdress.Length == 4)
                {
                    #region   actionpoint
                    switch (int.Parse(destAdress))
                    {
                        //sc1

                        case 1512: actionpoint = 2; break;  //入库
                        case 1510: actionpoint = 3; break;  //入库
                        case 1702: actionpoint = 4; break;  //出库
                        case 1701: actionpoint = 5; break;  //出库




                        //sc2 
                        case 1035: actionpoint = 2; break;  //A区一层入库
                        case 1033: actionpoint = 2; break;  //A区一层入库
                        case 1405: actionpoint = 3; break;  //A区二层入库
                        case 1407: actionpoint = 3; break;  //A区二层入库
                      //  case 1702: actionpoint = 4; break;  //A区三层出库
                        case 1704: actionpoint = 4; break;  //A区三层出库
                        case 1081: actionpoint = 5; break;  //B区一层入库
                        case 1079: actionpoint = 5; break;  //B区一层入库
                        case 1418: actionpoint = 6; break;  //B区二层出库
                        case 1416: actionpoint = 6; break;  //B区二层出库
                        //sc3 
                        case 1093: actionpoint = 2; break;  //入库取货
                        case 1095: actionpoint = 2; break;  //入库取货
                        case 1438: actionpoint = 3; break;  //出库放货有死挡
                        case 1436: actionpoint = 3; break;  //出库放货无死挡
                        case 1125: actionpoint = 4; break;  //出库放货无死挡
                        case 1127: actionpoint = 4; break;  //出库放货无死挡
                        case 1497: actionpoint = 5; break;  //出库放货无死挡
                        case 1499: actionpoint = 5; break;  //出库放货无死挡
                        //sc4
                        case 1091: actionpoint = 2; break;  //一楼入库
                        case 1089: actionpoint = 2; break;  //一楼出库 无死挡  远离货架的站台
                        case 1447: actionpoint = 3; break;  //一楼出库 有死挡  靠近旋转台的站台
                        case 1445: actionpoint = 3; break;  //一楼出库 有死挡  靠近旋转台的站台
                        case 1104: actionpoint = 4; break;  //一楼出库 有死挡  靠近旋转台的站台
                        case 1102: actionpoint = 4; break;  //一楼出库 有死挡  靠近旋转台的站台
                        case 1507: actionpoint = 5; break;  //一楼出库 有死挡  靠近旋转台的站台
                        case 1509: actionpoint = 5; break;  //一楼出库 有死挡  靠近旋转台的站台
                        case 1761: actionpoint = 6; break;  //一楼出库 有死挡  靠近旋转台的站台
                        case 1763: actionpoint = 6; break;  //一楼出库 有死挡  靠近旋转台的站台

                        //SC5 常温库
                        case 1146: actionpoint = 2; break;  //二层左侧入库
                        case 1144: actionpoint = 2; break;  //一层左侧入库
                        case 1155: actionpoint = 3; break;  //二层右侧出库
                        case 1153: actionpoint = 3; break;  //一层右侧入库
                        case 1480: actionpoint = 4; break;  //二层左侧入库
                        case 1482: actionpoint = 4; break;  //一层左侧入库
                        case 1469: actionpoint = 5; break;  //二层右侧出库
                        case 1471: actionpoint = 5; break;  //一层右侧入库
                        case 1738: actionpoint = 6; break;  //二层右侧出库
                        case 1740: actionpoint = 6; break;  //一层右侧入库
                        case 1189: actionpoint = 7; break;  //一层左侧入库
                        case 1187: actionpoint = 7; break;  //二层左侧出库
                        case 1525: actionpoint = 8; break;  //一层右侧入库
                        case 1523: actionpoint = 8; break;  //二层右侧出库
                        //SC6 常温库
                        case 1163: actionpoint = 2; break;  //一层左侧入库
                        case 1161: actionpoint = 2; break;  //二层左侧出库
                        case 1172: actionpoint = 3; break;  //一层右侧入库
                        case 1170: actionpoint = 3; break;  //二层右侧出库
                        case 1465: actionpoint = 4; break;  //一层左侧入库
                        case 1463: actionpoint = 4; break;  //二层左侧出库
                        case 1449: actionpoint = 5; break;  //一层右侧入库
                        case 1451: actionpoint = 5; break;  //二层右侧出库
                        case 1728: actionpoint = 6; break;  //一层右侧入库
                        case 1730: actionpoint = 6; break;  //二层右侧出库
                        case 1198: actionpoint = 7; break;  //一层左侧入库
                        case 1200: actionpoint = 7; break;  //二层左侧出库
                        case 1515: actionpoint = 8; break;  //一层右侧入库
                        case 1513: actionpoint = 8; break;  //二层右侧出库
                    }
                    #endregion

                    for (int i = 12; i < 24; i++)
                    {
                        msg[i] = 0x00;
                    }

                }
                //取放指令为：货架
                else if (destAdress != null && destAdress.Length > 8)  //0504606
                {

                    int row = int.Parse(destAdress.Substring(0, 3)) % 2 == 0 ? 2 : 1;
                    int Column = int.Parse(destAdress.Substring(3, 3));
                    int layer = int.Parse(destAdress.Substring(6, 3));
                    int depth = 1;
                    msg[12] = (byte)row;
                    msg[13] = (byte)Column;  //直接给列数，无货格概念
                    msg[14] = (byte)1;
                    msg[15] = (byte)(layer);//层,1-9
                    msg[16] = (byte)(depth);//深 1-2
                    for (int i = 17; i < 24; i++)
                    {
                        msg[i] = 0x00;
                    }
                }
                msg[10] = (byte)actionpoint;
                msg[11] = (byte)aisle1;//巷道
                msg[21] = (byte)(int.Parse(fireflag));
                bool sendflag = OSRM.SendMsg(msg);
                if (sendflag)
                {
                    WriteLog("S", "堆垛机编号:" + scno + "发送指令成功:" + type.ToString() + "工位1任务号:" + taskno.ToString() + "工位2任务号:" + fork2taskno.ToString() + "地址:" + destAdress + ",货叉:" + forkNo);
                }
                else
                {
                    WriteLog("S", "堆垛机编号:" + scno + "发送指令失败:" + type.ToString() + "工位1任务号:" + taskno.ToString() + "工位2任务号:" + fork2taskno.ToString() + "地址:" + destAdress + ",货叉:" + forkNo);
                }
                return sendflag;
            }
            catch (Exception ee)
            {
                WriteLog("S", "堆垛机编号:" + scno + "发送指令异常:" + type.ToString() + "/" + taskno.ToString() + "/" + destAdress + "  " + ee.Message);
                return false;
            }
        }

        public void WriteLog(string type, string msg)
        {
            if (!string.IsNullOrEmpty(msg))
            {
                ShowText(type, msg);
                if (type == "S")
                {
                    log.Info(msg);
                }
                else
                {
                    logConnect.Info(msg);
                }
            }
        }
        /// <summary>
        /// 下发任务
        /// </summary>
        /// <param name="num">堆垛机编号</param>
        /// <param name="taskno">工位1任务号</param>
        /// <param name="fromstation">工位1起始地址</param>
        /// <param name="tostation">工位1目标地址</param>
        /// <param name="statostation">工位1输送机目标地址</param>
        /// <param name="tasktype">任务类型</param>
        /// <param name="forkNo">货叉下发命令值</param>
        /// <param name="taskno1">工位2任务号</param>
        /// <param name="fromstation1">工位2起始地址</param>
        /// <param name="tostation1">工位2目标地址</param>
        /// <param name="statostation1">工位2输送机目标地址</param>
        /// <returns></returns>
        public bool SendTask(string num, string taskno, string fromstation, string tostation, string statostation, string tasktype, int forkNo = 1, int taskno1=0, string fromstation1 = "", string tostation1 = "", string statostation1 = "")
        {
            try
            {
                if (crc.UpdateCRCTaskInfo(m_strSRMNo, fromstation.Trim('S'), tostation.Trim('S'), statostation, tasktype, forkNo, fromstation1, tostation1, statostation1))
                {
                    bool sendflag= false;
                    if (forkNo == 2)//货叉2取货，则下发货叉2的任务起始地址
                    {
                        if (taskno == taskno1.ToString())
                            taskno = "0";
                        sendflag = SendCode(num, CR_GETC, int.Parse(taskno), fromstation1, "0", forkNo, taskno1); //取货指令
                    }
                    else
                    {
                        if (taskno == taskno1.ToString())
                            taskno1 = 0;
                        sendflag = SendCode(num, CR_GETC, int.Parse(taskno), fromstation, "0", forkNo, taskno1); //取货指令
                    }
                    if (sendflag)
                    {
                        if (forkNo == 1 || forkNo == 3)
                        {
                            if (fromstation.Length == 4)
                            {
                                ConveryBLL converyBLL = new ConveryBLL();
                                STACommand cmd = STACommand.ClearToStation;
                                converyBLL.WriteStationInfo(cmd, new string[2] { fromstation, "2" }, fromstation, 4, 2);
                            }
                            dal.UpdateTaskStatus(fromstation, taskno.ToString(), "", "SC", "2", "1"); //修改堆垛机货叉1任务状态
                            WriteLog("S", "堆垛机编号:" + num + "发送任务成功,货叉1任务号:" + taskno.ToString() + "  起止:" + fromstation + "-->" + tostation);
                        }
                        if (forkNo == 2|| forkNo == 3)
                        {
                            if (fromstation1.Length == 4)
                            {
                                ConveryBLL converyBLL = new ConveryBLL();
                                STACommand cmd = STACommand.ClearToStation;
                                converyBLL.WriteStationInfo(cmd, new string[2] { fromstation1, "2" }, fromstation1, 4, 2);
                            }
                            dal.UpdateTaskStatus(fromstation1, taskno1.ToString(), "", "SC", "2", "1"); //修改堆垛机货叉2任务状态
                            WriteLog("S", "堆垛机编号:" + num + "发送任务成功,货叉2任务号:" + taskno1.ToString() + "  起止:" + fromstation1 + "-->" + tostation1);
                        }
                    }
                    else
                    {
                        WriteLog( "S", "堆垛机编号:" + num + "发送任务发送失败,任务号:" + taskno.ToString() + "  起止:" + fromstation + "-->" + tostation);
                    }
                    return sendflag;
                }
                else
                {
                    WriteLog("S", "堆垛机编号:" + num + "发送任务更新失败,任务号:" + taskno.ToString() + "  起止:" + fromstation + "-->" + tostation);
                    return false;
                }
            }
            catch (Exception ee)
            {
                WriteLog("S", "堆垛机编号:" + num + "发送任务异常:" + taskno + "(" + fromstation + "-->" + tostation + ") " + ee.ToString());
                return false;
            }
        }

        public string getTasktype(string TaskType)
        {
            if (TaskType == "All")
            {
                return "正常出入";
            }
            else if (TaskType == "None")
            {
                return "暂停任务";
            }
            else if (TaskType == "Task_InBound")
            {
                return "仅入库";
            }
            else if (TaskType == "Task_OutBound")
            {
                return "仅出库";
            }
            return null;
        }

        public string getForktype(string TaskType)
        {
            if (TaskType == "forkNo")
            {
                return "双货叉";
            }
            else if (TaskType == "forkNo1")
            {
                return "货叉1";
            }
            else if (TaskType == "forkNo2")
            {
                return "货叉2";
            }
            return null;
        }
        public void ShowText(string type, string msg)
        {
            if (ENotify != null)
            {
                ENotify(type, msg);
            }
        }
    }
}
